Carga inicial del dataframe de tweets COVID-19

library(tidyverse)
library(mongolite)
library(ggplot2)
library(plotly)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(hrbrthemes)
NOTE: Either Arial Narrow or Roboto Condensed fonts are required to use these themes.
      Please use hrbrthemes::import_roboto_condensed() to install Roboto Condensed and
      if Arial Narrow is not on your system, please see https://bit.ly/arialnarrow
library(dplyr)
library(here)

tweets_mongo_covid19 <- mongo(
  collection = "tweets_mongo_covid19", 
  db = "DMUBA"
)

hitos_df <- read.csv(
  here("resources" , "hitos_discretizado.csv")
)

Mongo Query

df_tweets = tweets_mongo_covid19$aggregate(
'[
  {
      "$match": {}
  },
  {
      "$project": {
      
      "status_id": 1,
      "user_id": 1,
      "screen_name": 1,
      "verified": 1,
      "location": 1,
      "source": 1,
      "favorite_count": 1,
      "retweet_count": 1,
      "created_at": {
        "$dateToString": { "date": "$created_at"}
      },

      "retweet_status_id": 1,  
      "retweet_user_id": 1,
      "retweet_screen_name": 1,
      "retweet_verified": 1,
      "retweet_location": 1,
      "retweet_source": 1,
      "retweet_favorite_count": 1,
      "retweet_retweet_count": 1,
      "retweet_created_at": {
        "$cond": { 
          "if": { 
            "$eq" : ["$retweet_created_at", {}] 
          }, 
          "then": null, 
          "else": {
            "$dateToString": {"date": "$retweet_created_at"}
          }
        }
      },
            
      "quoted_status_id": 1,  
      "quoted_user_id": 1,
      "quoted_screen_name": 1,
      "quoted_verified": 1,
      "quoted_location": 1,
      "quoted_source": 1,
      "quoted_favorite_count": 1,
      "quoted_retweet_count": 1,
      "quoted_created_at": {
        "$cond": { 
          "if": { 
            "$eq" : ["$quoted_created_at", {}] 
          }, 
          "then": null, 
          "else": {
            "$dateToString": {"date": "$quoted_created_at"}
          }
        }
      }
    }
  }
]'
)

Unificamos tweets originales, retweets y quotes bajo atributos comunes. ( ‘status_id’, ‘user_id’, ‘screen_name’, ‘verified’, ‘location’, ‘source’, ‘favorite_count’, ‘retweet_count’, ‘created_at’ )

# Original Tweets
original_tweets_header <- c(
  'status_id',
  'user_id',
  'screen_name',
  'verified',
  'location',
  'source',
  'favorite_count',
  'retweet_count',
  'created_at'
)
original_tweets = df_tweets[,original_tweets_header]

# Retweets
retweeted_tweets_header <- c(
  'retweet_status_id',
  'retweet_user_id',
  'retweet_screen_name',
  'retweet_verified',
  'retweet_location',
  'retweet_source',
  'retweet_favorite_count',
  'retweet_retweet_count',
  'retweet_created_at'
)

retweeted_tweets = df_tweets[,retweeted_tweets_header]

names(retweeted_tweets)[names(retweeted_tweets) == 'retweet_status_id'] <- 'status_id'
names(retweeted_tweets)[names(retweeted_tweets) == 'retweet_user_id'] <- 'user_id'
names(retweeted_tweets)[names(retweeted_tweets) == 'retweet_screen_name'] <- 'screen_name'
names(retweeted_tweets)[names(retweeted_tweets) == 'retweet_verified'] <- 'verified'
names(retweeted_tweets)[names(retweeted_tweets) == 'retweet_location'] <- 'location'
names(retweeted_tweets)[names(retweeted_tweets) == 'retweet_source'] <- 'source'
names(retweeted_tweets)[names(retweeted_tweets) == 'retweet_favorite_count'] <- 'favorite_count'
names(retweeted_tweets)[names(retweeted_tweets) == 'retweet_retweet_count'] <- 'retweet_count'
names(retweeted_tweets)[names(retweeted_tweets) == 'retweet_created_at'] <- 'created_at'

# Quotes
quoted_tweets_header <- c(
  'quoted_status_id',
  'quoted_user_id',
  'quoted_screen_name',
  'quoted_verified',
  'quoted_location',
  'quoted_source',
  'quoted_favorite_count',
  'quoted_retweet_count',
  'quoted_created_at'
)

quoted_tweets = df_tweets[,quoted_tweets_header]

names(quoted_tweets)[names(quoted_tweets) == 'quoted_status_id'] <- 'status_id'
names(quoted_tweets)[names(quoted_tweets) == 'quoted_user_id'] <- 'user_id'
names(quoted_tweets)[names(quoted_tweets) == 'quoted_screen_name'] <- 'screen_name'
names(quoted_tweets)[names(quoted_tweets) == 'quoted_verified'] <- 'verified'
names(quoted_tweets)[names(quoted_tweets) == 'quoted_location'] <- 'location'
names(quoted_tweets)[names(quoted_tweets) == 'quoted_source'] <- 'source'
names(quoted_tweets)[names(quoted_tweets) == 'quoted_favorite_count'] <- 'favorite_count'
names(quoted_tweets)[names(quoted_tweets) == 'quoted_retweet_count'] <- 'retweet_count'
names(quoted_tweets)[names(quoted_tweets) == 'quoted_created_at'] <- 'created_at'

Combinamos los tweets y aplicamos formateo a los valores de fecha

combined_tweets = rbind(original_tweets, retweeted_tweets, quoted_tweets)

combined_tweets['created_at_R_date'] = as.POSIXct(
  combined_tweets$created_at, 
  format="%Y-%m-%dT", 
  tz="UTC"
)
combined_tweets['created_at'] = as.POSIXct(
  combined_tweets$created_at, 
  format="%Y-%m-%dT%H:%M:%S", 
  tz="UTC"
)
# Limpiamos duplicados
combined_tweets = combined_tweets[!duplicated(combined_tweets),]
combined_tweets[!is.na(combined_tweets['created_at_R_date']),]
NA

Transformamos nuestro dataset de hitos

hitos_df['Fecha'] = as.Date(hitos_df$Fecha, "%d/%m/%Y")
hitos_df['Primera'] <- ifelse(hitos_df['Primera'] == "S", 1, 0) 
tweet_counts_by_date = as.data.frame(
  combined_tweets %>%
  group_by(created_at_R_date) %>%
  count(created_at_R_date)
)
names(tweet_counts_by_date)[1] = 'date'
names(tweet_counts_by_date)[2] = 'count'
  
summary(hitos_df)
     Fecha                                        Evento     Primera.Primera  
 Min.   :2020-04-25   Prisiones domiciliarias        : 7   Min.   :0.0000000  
 1st Qu.:2020-05-01   AMBA Flexibilización 500m      : 2   1st Qu.:1.0000000  
 Median :2020-05-06   CuidAR                         : 2   Median :1.0000000  
 Mean   :2020-05-06   Deuda: Bonistas Rechazan Oferta: 2   Mean   :0.8275862  
 3rd Qu.:2020-05-11   Expaña Flexibilización         : 2   3rd Qu.:1.0000000  
 Max.   :2020-05-15   Extensión Cuarentena           : 2   Max.   :1.0000000  
                      (Other)                        :41                      
# From summary
hitos_min_date=as.POSIXct("2020-04-25")
hitos_max_date=as.POSIXct("2020-05-15")

tweet_counts_by_date_range = as.data.frame(
  tweet_counts_by_date %>%
    filter(date >= hitos_min_date & date <= hitos_max_date)
)

summary(tweet_counts_by_date_range)
      date                         count        
 Min.   :2020-04-26 00:00:00   Min.   :   39.0  
 1st Qu.:2020-04-30 18:00:00   1st Qu.:  403.5  
 Median :2020-05-05 12:00:00   Median : 2248.0  
 Mean   :2020-05-05 12:00:00   Mean   : 2673.7  
 3rd Qu.:2020-05-10 06:00:00   3rd Qu.: 3063.0  
 Max.   :2020-05-15 00:00:00   Max.   :16626.0  

Graficamos la cantidad de tweets por día

# Usual area chart
p <- tweet_counts_by_date_range %>%
  ggplot( aes(x=date, y=count)) +
    geom_area(fill="#69b3a2", alpha=0.5) +
    geom_line(color="#69b3a2") +
    ylab("tweets by news events dates") +
    theme_ipsum()

# Turn it interactive with ggplotly
p <- ggplotly(p)
p

Exploramos el uso de hashtags

Ya teniendo una primera impresión de la evolución de los tweets en base sus fechas, exploramos el uso de hashtags

expanded_hashtags = tweets_mongo_covid19$aggregate(
'[
    {
        "$unwind": "$hashtags"
    },
    {
        "$project": {
            "status_id": 1,
            "verified": 1,
            "location": 1,
            "source": 1,
            "created_at": {
                "$dateToString": { "date": "$created_at"}
            },
            "favorite_count": 1,
            "retweet_count": 1,

            "retweet_status_id": 1,
            "retweet_verified": 1,
            "retweet_location":1,
            "retweet_source": 1,
            "retweet_created_at": {
                "$cond": { 
                    "if": { 
                        "$eq" : ["$retweet_created_at", {}] 
                    }, 
                    "then": null, 
                    "else": {
                        "$dateToString": {"date": "$retweet_created_at"}
                    }
                }
            },
            "retweet_favorite_count": 1,
            "retweet_retweet_count": 1,

            "quoted_status_id": 1,
            "quoted_verified": 1,
            "quoted_location": 1,
            "quoted_source": 1, 
             "quoted_created_at": {
                "$cond": { 
                    "if": { 
                        "$eq" : ["$quoted_created_at", {}] 
                    }, 
                    "then": null, 
                    "else": {
                        "$dateToString": {"date": "$quoted_created_at"}
                    }
                }
            },
            "quoted_favorite_count": 1,
            "quoted_retweet_count": 1,

            "hashtags": 1
        }
    }
]'
)
original_tweet_headers <- c(
  'status_id',
  'verified',
  'location',
  'source',
  'created_at',
  'favorite_count',
  'retweet_count',
  'hashtags'
)
original_tweet_hashtags = expanded_hashtags[,original_tweet_headers]

# Retweets
retweeted_tweet_headers <- c(
  'retweet_status_id',
  'retweet_verified',
  'retweet_location',
  'retweet_source',
  'retweet_created_at',
  'retweet_favorite_count',
  'retweet_retweet_count',
  'hashtags'
)

retweeted_tweet_hashtags = expanded_hashtags[,retweeted_tweet_headers]

names(retweeted_tweet_hashtags)[names(retweeted_tweet_hashtags) == 'retweet_status_id'] <- 'status_id'
names(retweeted_tweet_hashtags)[names(retweeted_tweet_hashtags) == 'retweet_verified'] <- 'verified'
names(retweeted_tweet_hashtags)[names(retweeted_tweet_hashtags) == 'retweet_location'] <- 'location'
names(retweeted_tweet_hashtags)[names(retweeted_tweet_hashtags) == 'retweet_source'] <- 'source'
names(retweeted_tweet_hashtags)[names(retweeted_tweet_hashtags) == 'retweet_created_at'] <- 'created_at'
names(retweeted_tweet_hashtags)[names(retweeted_tweet_hashtags) == 'retweet_favorite_count'] <- 'favorite_count'
names(retweeted_tweet_hashtags)[names(retweeted_tweet_hashtags) == 'retweet_retweet_count'] <- 'retweet_count'

# Quotes
quoted_tweet_headers <- c(
  'quoted_status_id',
  'quoted_verified',
  'quoted_location',
  'quoted_source',
  'quoted_created_at',
  'quoted_favorite_count',
  'quoted_retweet_count',
  'hashtags'
)
quoted_tweet_hashtags = expanded_hashtags[,quoted_tweet_headers]

names(quoted_tweet_hashtags)[names(quoted_tweet_hashtags) == 'quoted_status_id'] <- 'status_id'
names(quoted_tweet_hashtags)[names(quoted_tweet_hashtags) == 'quoted_verified'] <- 'verified'
names(quoted_tweet_hashtags)[names(quoted_tweet_hashtags) == 'quoted_location'] <- 'location'
names(quoted_tweet_hashtags)[names(quoted_tweet_hashtags) == 'quoted_source'] <- 'source'
names(quoted_tweet_hashtags)[names(quoted_tweet_hashtags) == 'quoted_created_at'] <- 'created_at'
names(quoted_tweet_hashtags)[names(quoted_tweet_hashtags) == 'quoted_favorite_count'] <- 'favorite_count'
names(quoted_tweet_hashtags)[names(quoted_tweet_hashtags) == 'quoted_retweet_count'] <- 'retweet_count'
combined_hashtags = rbind(original_tweet_hashtags, retweeted_tweet_hashtags, quoted_tweet_hashtags)

combined_hashtags['created_at_R_date'] = as.POSIXct(
  combined_hashtags$created_at, 
  format="%Y-%m-%dT", 
  tz="UTC"
)
combined_hashtags['created_at'] = as.POSIXct(
  combined_hashtags$created_at, 
  format="%Y-%m-%dT%H:%M:%S", 
  tz="UTC"
)

# Limpiamos duplicados
combined_hashtags = combined_hashtags[!duplicated(combined_hashtags),]
combined_hashtags[!is.na(combined_hashtags['created_at_R_date']),]
hashtags_counts_by_date = as.data.frame(
  combined_hashtags %>%
  group_by(created_at_R_date, hashtags) %>%
  count(hashtags)
)

names(hashtags_counts_by_date)[1] = 'date'
names(hashtags_counts_by_date)[3] = 'count'

# Elimino todos los tweets sin hashtags (NA)
hashtags_counts_by_date = hashtags_counts_by_date[!is.na(hashtags_counts_by_date['hashtags']),]
# Elimino ahora valores de hashtags que considero genéricos o de clasificación 
# Estos hashtags no agregan valor al contenido
filtered_hashtag_counts_by_date = as.data.frame(
  hashtags_counts_by_date %>%
  filter(
    !str_detect(str_to_lower(hashtags), str_to_lower(".*COVID.*|.*coronavirus.*"))
  )
)

# From summary
hitos_min_date=as.POSIXct("2020-04-25")
hitos_max_date=as.POSIXct("2020-05-15")

filtered_hashtag_counts_by_date_range = as.data.frame(
  filtered_hashtag_counts_by_date %>%
    filter(date >= hitos_min_date & date <= hitos_max_date)
)

# Consigo el hashtag mas usado para un determinado día
top_hashtags_by_news_date = as.data.frame(
  filtered_hashtag_counts_by_date_range %>% 
  group_by(date) %>% 
  top_n(1, count)
)

# Me quedo con los que tienen valores significativos (> 3)
top_hashtags_by_news_date = top_hashtags_by_news_date[top_hashtags_by_news_date["count"]>3,]

Graficamos los hashtags mas usados por día (evaluando contenido)


p2 <- top_hashtags_by_news_date %>%
  ggplot( aes(x=date, y=count, size=count, color=hashtags)) +
  geom_point() +
  ggtitle("most used hashtag by date") +
  xlab("date")  +
  ylab("times used")  +
  theme_bw()

ggplotly(p2)
LS0tCnRpdGxlOiAiRE1VQkEgVFAwMSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKQ2FyZ2EgaW5pY2lhbCBkZWwgZGF0YWZyYW1lIGRlIHR3ZWV0cyBDT1ZJRC0xOQpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobW9uZ29saXRlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGhyYnJ0aGVtZXMpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoaGVyZSkKCnR3ZWV0c19tb25nb19jb3ZpZDE5IDwtIG1vbmdvKAogIGNvbGxlY3Rpb24gPSAidHdlZXRzX21vbmdvX2NvdmlkMTkiLCAKICBkYiA9ICJETVVCQSIKKQoKaGl0b3NfZGYgPC0gcmVhZC5jc3YoCiAgaGVyZSgicmVzb3VyY2VzIiAsICJoaXRvc19kaXNjcmV0aXphZG8uY3N2IikKKQpgYGAKCk1vbmdvIFF1ZXJ5CmBgYHtyfQpkZl90d2VldHMgPSB0d2VldHNfbW9uZ29fY292aWQxOSRhZ2dyZWdhdGUoCidbCiAgewogICAgICAiJG1hdGNoIjoge30KICB9LAogIHsKICAgICAgIiRwcm9qZWN0IjogewogICAgICAKICAgICAgInN0YXR1c19pZCI6IDEsCiAgICAgICJ1c2VyX2lkIjogMSwKICAgICAgInNjcmVlbl9uYW1lIjogMSwKICAgICAgInZlcmlmaWVkIjogMSwKICAgICAgImxvY2F0aW9uIjogMSwKICAgICAgInNvdXJjZSI6IDEsCiAgICAgICJmYXZvcml0ZV9jb3VudCI6IDEsCiAgICAgICJyZXR3ZWV0X2NvdW50IjogMSwKICAgICAgImNyZWF0ZWRfYXQiOiB7CiAgICAgICAgIiRkYXRlVG9TdHJpbmciOiB7ICJkYXRlIjogIiRjcmVhdGVkX2F0In0KICAgICAgfSwKCiAgICAgICJyZXR3ZWV0X3N0YXR1c19pZCI6IDEsICAKICAgICAgInJldHdlZXRfdXNlcl9pZCI6IDEsCiAgICAgICJyZXR3ZWV0X3NjcmVlbl9uYW1lIjogMSwKICAgICAgInJldHdlZXRfdmVyaWZpZWQiOiAxLAogICAgICAicmV0d2VldF9sb2NhdGlvbiI6IDEsCiAgICAgICJyZXR3ZWV0X3NvdXJjZSI6IDEsCiAgICAgICJyZXR3ZWV0X2Zhdm9yaXRlX2NvdW50IjogMSwKICAgICAgInJldHdlZXRfcmV0d2VldF9jb3VudCI6IDEsCiAgICAgICJyZXR3ZWV0X2NyZWF0ZWRfYXQiOiB7CiAgICAgICAgIiRjb25kIjogeyAKICAgICAgICAgICJpZiI6IHsgCiAgICAgICAgICAgICIkZXEiIDogWyIkcmV0d2VldF9jcmVhdGVkX2F0Iiwge31dIAogICAgICAgICAgfSwgCiAgICAgICAgICAidGhlbiI6IG51bGwsIAogICAgICAgICAgImVsc2UiOiB7CiAgICAgICAgICAgICIkZGF0ZVRvU3RyaW5nIjogeyJkYXRlIjogIiRyZXR3ZWV0X2NyZWF0ZWRfYXQifQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSwKICAgICAgICAgICAgCiAgICAgICJxdW90ZWRfc3RhdHVzX2lkIjogMSwgIAogICAgICAicXVvdGVkX3VzZXJfaWQiOiAxLAogICAgICAicXVvdGVkX3NjcmVlbl9uYW1lIjogMSwKICAgICAgInF1b3RlZF92ZXJpZmllZCI6IDEsCiAgICAgICJxdW90ZWRfbG9jYXRpb24iOiAxLAogICAgICAicXVvdGVkX3NvdXJjZSI6IDEsCiAgICAgICJxdW90ZWRfZmF2b3JpdGVfY291bnQiOiAxLAogICAgICAicXVvdGVkX3JldHdlZXRfY291bnQiOiAxLAogICAgICAicXVvdGVkX2NyZWF0ZWRfYXQiOiB7CiAgICAgICAgIiRjb25kIjogeyAKICAgICAgICAgICJpZiI6IHsgCiAgICAgICAgICAgICIkZXEiIDogWyIkcXVvdGVkX2NyZWF0ZWRfYXQiLCB7fV0gCiAgICAgICAgICB9LCAKICAgICAgICAgICJ0aGVuIjogbnVsbCwgCiAgICAgICAgICAiZWxzZSI6IHsKICAgICAgICAgICAgIiRkYXRlVG9TdHJpbmciOiB7ImRhdGUiOiAiJHF1b3RlZF9jcmVhdGVkX2F0In0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cl0nCikKYGBgCgpVbmlmaWNhbW9zIHR3ZWV0cyBvcmlnaW5hbGVzLCByZXR3ZWV0cyB5IHF1b3RlcyBiYWpvIGF0cmlidXRvcyBjb211bmVzLgooCiAgJ3N0YXR1c19pZCcsCiAgJ3VzZXJfaWQnLAogICdzY3JlZW5fbmFtZScsCiAgJ3ZlcmlmaWVkJywKICAnbG9jYXRpb24nLAogICdzb3VyY2UnLAogICdmYXZvcml0ZV9jb3VudCcsCiAgJ3JldHdlZXRfY291bnQnLAogICdjcmVhdGVkX2F0JwopCmBgYHtyfQojIE9yaWdpbmFsIFR3ZWV0cwpvcmlnaW5hbF90d2VldHNfaGVhZGVyIDwtIGMoCiAgJ3N0YXR1c19pZCcsCiAgJ3VzZXJfaWQnLAogICdzY3JlZW5fbmFtZScsCiAgJ3ZlcmlmaWVkJywKICAnbG9jYXRpb24nLAogICdzb3VyY2UnLAogICdmYXZvcml0ZV9jb3VudCcsCiAgJ3JldHdlZXRfY291bnQnLAogICdjcmVhdGVkX2F0JwopCm9yaWdpbmFsX3R3ZWV0cyA9IGRmX3R3ZWV0c1ssb3JpZ2luYWxfdHdlZXRzX2hlYWRlcl0KCiMgUmV0d2VldHMKcmV0d2VldGVkX3R3ZWV0c19oZWFkZXIgPC0gYygKICAncmV0d2VldF9zdGF0dXNfaWQnLAogICdyZXR3ZWV0X3VzZXJfaWQnLAogICdyZXR3ZWV0X3NjcmVlbl9uYW1lJywKICAncmV0d2VldF92ZXJpZmllZCcsCiAgJ3JldHdlZXRfbG9jYXRpb24nLAogICdyZXR3ZWV0X3NvdXJjZScsCiAgJ3JldHdlZXRfZmF2b3JpdGVfY291bnQnLAogICdyZXR3ZWV0X3JldHdlZXRfY291bnQnLAogICdyZXR3ZWV0X2NyZWF0ZWRfYXQnCikKCnJldHdlZXRlZF90d2VldHMgPSBkZl90d2VldHNbLHJldHdlZXRlZF90d2VldHNfaGVhZGVyXQoKbmFtZXMocmV0d2VldGVkX3R3ZWV0cylbbmFtZXMocmV0d2VldGVkX3R3ZWV0cykgPT0gJ3JldHdlZXRfc3RhdHVzX2lkJ10gPC0gJ3N0YXR1c19pZCcKbmFtZXMocmV0d2VldGVkX3R3ZWV0cylbbmFtZXMocmV0d2VldGVkX3R3ZWV0cykgPT0gJ3JldHdlZXRfdXNlcl9pZCddIDwtICd1c2VyX2lkJwpuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRzKVtuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRzKSA9PSAncmV0d2VldF9zY3JlZW5fbmFtZSddIDwtICdzY3JlZW5fbmFtZScKbmFtZXMocmV0d2VldGVkX3R3ZWV0cylbbmFtZXMocmV0d2VldGVkX3R3ZWV0cykgPT0gJ3JldHdlZXRfdmVyaWZpZWQnXSA8LSAndmVyaWZpZWQnCm5hbWVzKHJldHdlZXRlZF90d2VldHMpW25hbWVzKHJldHdlZXRlZF90d2VldHMpID09ICdyZXR3ZWV0X2xvY2F0aW9uJ10gPC0gJ2xvY2F0aW9uJwpuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRzKVtuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRzKSA9PSAncmV0d2VldF9zb3VyY2UnXSA8LSAnc291cmNlJwpuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRzKVtuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRzKSA9PSAncmV0d2VldF9mYXZvcml0ZV9jb3VudCddIDwtICdmYXZvcml0ZV9jb3VudCcKbmFtZXMocmV0d2VldGVkX3R3ZWV0cylbbmFtZXMocmV0d2VldGVkX3R3ZWV0cykgPT0gJ3JldHdlZXRfcmV0d2VldF9jb3VudCddIDwtICdyZXR3ZWV0X2NvdW50JwpuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRzKVtuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRzKSA9PSAncmV0d2VldF9jcmVhdGVkX2F0J10gPC0gJ2NyZWF0ZWRfYXQnCgojIFF1b3RlcwpxdW90ZWRfdHdlZXRzX2hlYWRlciA8LSBjKAogICdxdW90ZWRfc3RhdHVzX2lkJywKICAncXVvdGVkX3VzZXJfaWQnLAogICdxdW90ZWRfc2NyZWVuX25hbWUnLAogICdxdW90ZWRfdmVyaWZpZWQnLAogICdxdW90ZWRfbG9jYXRpb24nLAogICdxdW90ZWRfc291cmNlJywKICAncXVvdGVkX2Zhdm9yaXRlX2NvdW50JywKICAncXVvdGVkX3JldHdlZXRfY291bnQnLAogICdxdW90ZWRfY3JlYXRlZF9hdCcKKQoKcXVvdGVkX3R3ZWV0cyA9IGRmX3R3ZWV0c1sscXVvdGVkX3R3ZWV0c19oZWFkZXJdCgpuYW1lcyhxdW90ZWRfdHdlZXRzKVtuYW1lcyhxdW90ZWRfdHdlZXRzKSA9PSAncXVvdGVkX3N0YXR1c19pZCddIDwtICdzdGF0dXNfaWQnCm5hbWVzKHF1b3RlZF90d2VldHMpW25hbWVzKHF1b3RlZF90d2VldHMpID09ICdxdW90ZWRfdXNlcl9pZCddIDwtICd1c2VyX2lkJwpuYW1lcyhxdW90ZWRfdHdlZXRzKVtuYW1lcyhxdW90ZWRfdHdlZXRzKSA9PSAncXVvdGVkX3NjcmVlbl9uYW1lJ10gPC0gJ3NjcmVlbl9uYW1lJwpuYW1lcyhxdW90ZWRfdHdlZXRzKVtuYW1lcyhxdW90ZWRfdHdlZXRzKSA9PSAncXVvdGVkX3ZlcmlmaWVkJ10gPC0gJ3ZlcmlmaWVkJwpuYW1lcyhxdW90ZWRfdHdlZXRzKVtuYW1lcyhxdW90ZWRfdHdlZXRzKSA9PSAncXVvdGVkX2xvY2F0aW9uJ10gPC0gJ2xvY2F0aW9uJwpuYW1lcyhxdW90ZWRfdHdlZXRzKVtuYW1lcyhxdW90ZWRfdHdlZXRzKSA9PSAncXVvdGVkX3NvdXJjZSddIDwtICdzb3VyY2UnCm5hbWVzKHF1b3RlZF90d2VldHMpW25hbWVzKHF1b3RlZF90d2VldHMpID09ICdxdW90ZWRfZmF2b3JpdGVfY291bnQnXSA8LSAnZmF2b3JpdGVfY291bnQnCm5hbWVzKHF1b3RlZF90d2VldHMpW25hbWVzKHF1b3RlZF90d2VldHMpID09ICdxdW90ZWRfcmV0d2VldF9jb3VudCddIDwtICdyZXR3ZWV0X2NvdW50JwpuYW1lcyhxdW90ZWRfdHdlZXRzKVtuYW1lcyhxdW90ZWRfdHdlZXRzKSA9PSAncXVvdGVkX2NyZWF0ZWRfYXQnXSA8LSAnY3JlYXRlZF9hdCcKYGBgCgpDb21iaW5hbW9zIGxvcyB0d2VldHMgeSBhcGxpY2Ftb3MgZm9ybWF0ZW8gYSBsb3MgdmFsb3JlcyBkZSBmZWNoYQpgYGB7cn0KY29tYmluZWRfdHdlZXRzID0gcmJpbmQob3JpZ2luYWxfdHdlZXRzLCByZXR3ZWV0ZWRfdHdlZXRzLCBxdW90ZWRfdHdlZXRzKQoKY29tYmluZWRfdHdlZXRzWydjcmVhdGVkX2F0X1JfZGF0ZSddID0gYXMuUE9TSVhjdCgKICBjb21iaW5lZF90d2VldHMkY3JlYXRlZF9hdCwgCiAgZm9ybWF0PSIlWS0lbS0lZFQiLCAKICB0ej0iVVRDIgopCmNvbWJpbmVkX3R3ZWV0c1snY3JlYXRlZF9hdCddID0gYXMuUE9TSVhjdCgKICBjb21iaW5lZF90d2VldHMkY3JlYXRlZF9hdCwgCiAgZm9ybWF0PSIlWS0lbS0lZFQlSDolTTolUyIsIAogIHR6PSJVVEMiCikKIyBMaW1waWFtb3MgZHVwbGljYWRvcwpjb21iaW5lZF90d2VldHMgPSBjb21iaW5lZF90d2VldHNbIWR1cGxpY2F0ZWQoY29tYmluZWRfdHdlZXRzKSxdCmNvbWJpbmVkX3R3ZWV0c1shaXMubmEoY29tYmluZWRfdHdlZXRzWydjcmVhdGVkX2F0X1JfZGF0ZSddKSxdCgpgYGAKClRyYW5zZm9ybWFtb3MgbnVlc3RybyBkYXRhc2V0IGRlIGhpdG9zCmBgYHtyfQpoaXRvc19kZlsnRmVjaGEnXSA9IGFzLkRhdGUoaGl0b3NfZGYkRmVjaGEsICIlZC8lbS8lWSIpCmhpdG9zX2RmWydQcmltZXJhJ10gPC0gaWZlbHNlKGhpdG9zX2RmWydQcmltZXJhJ10gPT0gIlMiLCAxLCAwKSAKYGBgCgoKYGBge3J9CnR3ZWV0X2NvdW50c19ieV9kYXRlID0gYXMuZGF0YS5mcmFtZSgKICBjb21iaW5lZF90d2VldHMgJT4lCiAgZ3JvdXBfYnkoY3JlYXRlZF9hdF9SX2RhdGUpICU+JQogIGNvdW50KGNyZWF0ZWRfYXRfUl9kYXRlKQopCm5hbWVzKHR3ZWV0X2NvdW50c19ieV9kYXRlKVsxXSA9ICdkYXRlJwpuYW1lcyh0d2VldF9jb3VudHNfYnlfZGF0ZSlbMl0gPSAnY291bnQnCiAgCnN1bW1hcnkoaGl0b3NfZGYpCmBgYAoKYGBge3J9CiMgRnJvbSBzdW1tYXJ5CmhpdG9zX21pbl9kYXRlPWFzLlBPU0lYY3QoIjIwMjAtMDQtMjUiKQpoaXRvc19tYXhfZGF0ZT1hcy5QT1NJWGN0KCIyMDIwLTA1LTE1IikKCnR3ZWV0X2NvdW50c19ieV9kYXRlX3JhbmdlID0gYXMuZGF0YS5mcmFtZSgKICB0d2VldF9jb3VudHNfYnlfZGF0ZSAlPiUKICAgIGZpbHRlcihkYXRlID49IGhpdG9zX21pbl9kYXRlICYgZGF0ZSA8PSBoaXRvc19tYXhfZGF0ZSkKKQoKc3VtbWFyeSh0d2VldF9jb3VudHNfYnlfZGF0ZV9yYW5nZSkKYGBgCgpHcmFmaWNhbW9zIGxhIGNhbnRpZGFkIGRlIHR3ZWV0cyBwb3IgZMOtYQpgYGB7cn0KIyBVc3VhbCBhcmVhIGNoYXJ0CnAgPC0gdHdlZXRfY291bnRzX2J5X2RhdGVfcmFuZ2UgJT4lCiAgZ2dwbG90KCBhZXMoeD1kYXRlLCB5PWNvdW50KSkgKwogICAgZ2VvbV9hcmVhKGZpbGw9IiM2OWIzYTIiLCBhbHBoYT0wLjUpICsKICAgIGdlb21fbGluZShjb2xvcj0iIzY5YjNhMiIpICsKICAgIHlsYWIoInR3ZWV0cyBieSBuZXdzIGV2ZW50cyBkYXRlcyIpICsKICAgIHRoZW1lX2lwc3VtKCkKCiMgVHVybiBpdCBpbnRlcmFjdGl2ZSB3aXRoIGdncGxvdGx5CnAgPC0gZ2dwbG90bHkocCkKcApgYGAKCgojIEV4cGxvcmFtb3MgZWwgdXNvIGRlIGhhc2h0YWdzCllhIHRlbmllbmRvIHVuYSBwcmltZXJhIGltcHJlc2nDs24gZGUgbGEgZXZvbHVjacOzbiBkZSBsb3MgdHdlZXRzIGVuIGJhc2Ugc3VzIGZlY2hhcywgZXhwbG9yYW1vcyBlbCB1c28gZGUgaGFzaHRhZ3MKYGBge3J9CmV4cGFuZGVkX2hhc2h0YWdzID0gdHdlZXRzX21vbmdvX2NvdmlkMTkkYWdncmVnYXRlKAonWwogICAgewogICAgICAgICIkdW53aW5kIjogIiRoYXNodGFncyIKICAgIH0sCiAgICB7CiAgICAgICAgIiRwcm9qZWN0IjogewogICAgICAgICAgICAic3RhdHVzX2lkIjogMSwKICAgICAgICAgICAgInZlcmlmaWVkIjogMSwKICAgICAgICAgICAgImxvY2F0aW9uIjogMSwKICAgICAgICAgICAgInNvdXJjZSI6IDEsCiAgICAgICAgICAgICJjcmVhdGVkX2F0IjogewogICAgICAgICAgICAgICAgIiRkYXRlVG9TdHJpbmciOiB7ICJkYXRlIjogIiRjcmVhdGVkX2F0In0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgImZhdm9yaXRlX2NvdW50IjogMSwKICAgICAgICAgICAgInJldHdlZXRfY291bnQiOiAxLAoKICAgICAgICAgICAgInJldHdlZXRfc3RhdHVzX2lkIjogMSwKICAgICAgICAgICAgInJldHdlZXRfdmVyaWZpZWQiOiAxLAogICAgICAgICAgICAicmV0d2VldF9sb2NhdGlvbiI6MSwKICAgICAgICAgICAgInJldHdlZXRfc291cmNlIjogMSwKICAgICAgICAgICAgInJldHdlZXRfY3JlYXRlZF9hdCI6IHsKICAgICAgICAgICAgICAgICIkY29uZCI6IHsgCiAgICAgICAgICAgICAgICAgICAgImlmIjogeyAKICAgICAgICAgICAgICAgICAgICAgICAgIiRlcSIgOiBbIiRyZXR3ZWV0X2NyZWF0ZWRfYXQiLCB7fV0gCiAgICAgICAgICAgICAgICAgICAgfSwgCiAgICAgICAgICAgICAgICAgICAgInRoZW4iOiBudWxsLCAKICAgICAgICAgICAgICAgICAgICAiZWxzZSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgIiRkYXRlVG9TdHJpbmciOiB7ImRhdGUiOiAiJHJldHdlZXRfY3JlYXRlZF9hdCJ9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICAicmV0d2VldF9mYXZvcml0ZV9jb3VudCI6IDEsCiAgICAgICAgICAgICJyZXR3ZWV0X3JldHdlZXRfY291bnQiOiAxLAoKICAgICAgICAgICAgInF1b3RlZF9zdGF0dXNfaWQiOiAxLAogICAgICAgICAgICAicXVvdGVkX3ZlcmlmaWVkIjogMSwKICAgICAgICAgICAgInF1b3RlZF9sb2NhdGlvbiI6IDEsCiAgICAgICAgICAgICJxdW90ZWRfc291cmNlIjogMSwgCiAgICAgICAgICAgICAicXVvdGVkX2NyZWF0ZWRfYXQiOiB7CiAgICAgICAgICAgICAgICAiJGNvbmQiOiB7IAogICAgICAgICAgICAgICAgICAgICJpZiI6IHsgCiAgICAgICAgICAgICAgICAgICAgICAgICIkZXEiIDogWyIkcXVvdGVkX2NyZWF0ZWRfYXQiLCB7fV0gCiAgICAgICAgICAgICAgICAgICAgfSwgCiAgICAgICAgICAgICAgICAgICAgInRoZW4iOiBudWxsLCAKICAgICAgICAgICAgICAgICAgICAiZWxzZSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgIiRkYXRlVG9TdHJpbmciOiB7ImRhdGUiOiAiJHF1b3RlZF9jcmVhdGVkX2F0In0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJxdW90ZWRfZmF2b3JpdGVfY291bnQiOiAxLAogICAgICAgICAgICAicXVvdGVkX3JldHdlZXRfY291bnQiOiAxLAoKICAgICAgICAgICAgImhhc2h0YWdzIjogMQogICAgICAgIH0KICAgIH0KXScKKQpgYGAKCmBgYHtyfQpvcmlnaW5hbF90d2VldF9oZWFkZXJzIDwtIGMoCiAgJ3N0YXR1c19pZCcsCiAgJ3ZlcmlmaWVkJywKICAnbG9jYXRpb24nLAogICdzb3VyY2UnLAogICdjcmVhdGVkX2F0JywKICAnZmF2b3JpdGVfY291bnQnLAogICdyZXR3ZWV0X2NvdW50JywKICAnaGFzaHRhZ3MnCikKb3JpZ2luYWxfdHdlZXRfaGFzaHRhZ3MgPSBleHBhbmRlZF9oYXNodGFnc1ssb3JpZ2luYWxfdHdlZXRfaGVhZGVyc10KCiMgUmV0d2VldHMKcmV0d2VldGVkX3R3ZWV0X2hlYWRlcnMgPC0gYygKICAncmV0d2VldF9zdGF0dXNfaWQnLAogICdyZXR3ZWV0X3ZlcmlmaWVkJywKICAncmV0d2VldF9sb2NhdGlvbicsCiAgJ3JldHdlZXRfc291cmNlJywKICAncmV0d2VldF9jcmVhdGVkX2F0JywKICAncmV0d2VldF9mYXZvcml0ZV9jb3VudCcsCiAgJ3JldHdlZXRfcmV0d2VldF9jb3VudCcsCiAgJ2hhc2h0YWdzJwopCgpyZXR3ZWV0ZWRfdHdlZXRfaGFzaHRhZ3MgPSBleHBhbmRlZF9oYXNodGFnc1sscmV0d2VldGVkX3R3ZWV0X2hlYWRlcnNdCgpuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRfaGFzaHRhZ3MpW25hbWVzKHJldHdlZXRlZF90d2VldF9oYXNodGFncykgPT0gJ3JldHdlZXRfc3RhdHVzX2lkJ10gPC0gJ3N0YXR1c19pZCcKbmFtZXMocmV0d2VldGVkX3R3ZWV0X2hhc2h0YWdzKVtuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRfaGFzaHRhZ3MpID09ICdyZXR3ZWV0X3ZlcmlmaWVkJ10gPC0gJ3ZlcmlmaWVkJwpuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRfaGFzaHRhZ3MpW25hbWVzKHJldHdlZXRlZF90d2VldF9oYXNodGFncykgPT0gJ3JldHdlZXRfbG9jYXRpb24nXSA8LSAnbG9jYXRpb24nCm5hbWVzKHJldHdlZXRlZF90d2VldF9oYXNodGFncylbbmFtZXMocmV0d2VldGVkX3R3ZWV0X2hhc2h0YWdzKSA9PSAncmV0d2VldF9zb3VyY2UnXSA8LSAnc291cmNlJwpuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRfaGFzaHRhZ3MpW25hbWVzKHJldHdlZXRlZF90d2VldF9oYXNodGFncykgPT0gJ3JldHdlZXRfY3JlYXRlZF9hdCddIDwtICdjcmVhdGVkX2F0JwpuYW1lcyhyZXR3ZWV0ZWRfdHdlZXRfaGFzaHRhZ3MpW25hbWVzKHJldHdlZXRlZF90d2VldF9oYXNodGFncykgPT0gJ3JldHdlZXRfZmF2b3JpdGVfY291bnQnXSA8LSAnZmF2b3JpdGVfY291bnQnCm5hbWVzKHJldHdlZXRlZF90d2VldF9oYXNodGFncylbbmFtZXMocmV0d2VldGVkX3R3ZWV0X2hhc2h0YWdzKSA9PSAncmV0d2VldF9yZXR3ZWV0X2NvdW50J10gPC0gJ3JldHdlZXRfY291bnQnCgojIFF1b3RlcwpxdW90ZWRfdHdlZXRfaGVhZGVycyA8LSBjKAogICdxdW90ZWRfc3RhdHVzX2lkJywKICAncXVvdGVkX3ZlcmlmaWVkJywKICAncXVvdGVkX2xvY2F0aW9uJywKICAncXVvdGVkX3NvdXJjZScsCiAgJ3F1b3RlZF9jcmVhdGVkX2F0JywKICAncXVvdGVkX2Zhdm9yaXRlX2NvdW50JywKICAncXVvdGVkX3JldHdlZXRfY291bnQnLAogICdoYXNodGFncycKKQpxdW90ZWRfdHdlZXRfaGFzaHRhZ3MgPSBleHBhbmRlZF9oYXNodGFnc1sscXVvdGVkX3R3ZWV0X2hlYWRlcnNdCgpuYW1lcyhxdW90ZWRfdHdlZXRfaGFzaHRhZ3MpW25hbWVzKHF1b3RlZF90d2VldF9oYXNodGFncykgPT0gJ3F1b3RlZF9zdGF0dXNfaWQnXSA8LSAnc3RhdHVzX2lkJwpuYW1lcyhxdW90ZWRfdHdlZXRfaGFzaHRhZ3MpW25hbWVzKHF1b3RlZF90d2VldF9oYXNodGFncykgPT0gJ3F1b3RlZF92ZXJpZmllZCddIDwtICd2ZXJpZmllZCcKbmFtZXMocXVvdGVkX3R3ZWV0X2hhc2h0YWdzKVtuYW1lcyhxdW90ZWRfdHdlZXRfaGFzaHRhZ3MpID09ICdxdW90ZWRfbG9jYXRpb24nXSA8LSAnbG9jYXRpb24nCm5hbWVzKHF1b3RlZF90d2VldF9oYXNodGFncylbbmFtZXMocXVvdGVkX3R3ZWV0X2hhc2h0YWdzKSA9PSAncXVvdGVkX3NvdXJjZSddIDwtICdzb3VyY2UnCm5hbWVzKHF1b3RlZF90d2VldF9oYXNodGFncylbbmFtZXMocXVvdGVkX3R3ZWV0X2hhc2h0YWdzKSA9PSAncXVvdGVkX2NyZWF0ZWRfYXQnXSA8LSAnY3JlYXRlZF9hdCcKbmFtZXMocXVvdGVkX3R3ZWV0X2hhc2h0YWdzKVtuYW1lcyhxdW90ZWRfdHdlZXRfaGFzaHRhZ3MpID09ICdxdW90ZWRfZmF2b3JpdGVfY291bnQnXSA8LSAnZmF2b3JpdGVfY291bnQnCm5hbWVzKHF1b3RlZF90d2VldF9oYXNodGFncylbbmFtZXMocXVvdGVkX3R3ZWV0X2hhc2h0YWdzKSA9PSAncXVvdGVkX3JldHdlZXRfY291bnQnXSA8LSAncmV0d2VldF9jb3VudCcKYGBgCgpgYGB7cn0KY29tYmluZWRfaGFzaHRhZ3MgPSByYmluZChvcmlnaW5hbF90d2VldF9oYXNodGFncywgcmV0d2VldGVkX3R3ZWV0X2hhc2h0YWdzLCBxdW90ZWRfdHdlZXRfaGFzaHRhZ3MpCgpjb21iaW5lZF9oYXNodGFnc1snY3JlYXRlZF9hdF9SX2RhdGUnXSA9IGFzLlBPU0lYY3QoCiAgY29tYmluZWRfaGFzaHRhZ3MkY3JlYXRlZF9hdCwgCiAgZm9ybWF0PSIlWS0lbS0lZFQiLCAKICB0ej0iVVRDIgopCmNvbWJpbmVkX2hhc2h0YWdzWydjcmVhdGVkX2F0J10gPSBhcy5QT1NJWGN0KAogIGNvbWJpbmVkX2hhc2h0YWdzJGNyZWF0ZWRfYXQsIAogIGZvcm1hdD0iJVktJW0tJWRUJUg6JU06JVMiLCAKICB0ej0iVVRDIgopCgojIExpbXBpYW1vcyBkdXBsaWNhZG9zCmNvbWJpbmVkX2hhc2h0YWdzID0gY29tYmluZWRfaGFzaHRhZ3NbIWR1cGxpY2F0ZWQoY29tYmluZWRfaGFzaHRhZ3MpLF0KY29tYmluZWRfaGFzaHRhZ3NbIWlzLm5hKGNvbWJpbmVkX2hhc2h0YWdzWydjcmVhdGVkX2F0X1JfZGF0ZSddKSxdCmBgYAoKCmBgYHtyfQpoYXNodGFnc19jb3VudHNfYnlfZGF0ZSA9IGFzLmRhdGEuZnJhbWUoCiAgY29tYmluZWRfaGFzaHRhZ3MgJT4lCiAgZ3JvdXBfYnkoY3JlYXRlZF9hdF9SX2RhdGUsIGhhc2h0YWdzKSAlPiUKICBjb3VudChoYXNodGFncykKKQoKbmFtZXMoaGFzaHRhZ3NfY291bnRzX2J5X2RhdGUpWzFdID0gJ2RhdGUnCm5hbWVzKGhhc2h0YWdzX2NvdW50c19ieV9kYXRlKVszXSA9ICdjb3VudCcKCiMgRWxpbWlubyB0b2RvcyBsb3MgdHdlZXRzIHNpbiBoYXNodGFncyAoTkEpCmhhc2h0YWdzX2NvdW50c19ieV9kYXRlID0gaGFzaHRhZ3NfY291bnRzX2J5X2RhdGVbIWlzLm5hKGhhc2h0YWdzX2NvdW50c19ieV9kYXRlWydoYXNodGFncyddKSxdCgpgYGAKCmBgYHtyfQojIEVsaW1pbm8gYWhvcmEgdmFsb3JlcyBkZSBoYXNodGFncyBxdWUgY29uc2lkZXJvIGdlbsOpcmljb3MgbyBkZSBjbGFzaWZpY2FjacOzbiAKIyBFc3RvcyBoYXNodGFncyBubyBhZ3JlZ2FuIHZhbG9yIGFsIGNvbnRlbmlkbwpmaWx0ZXJlZF9oYXNodGFnX2NvdW50c19ieV9kYXRlID0gYXMuZGF0YS5mcmFtZSgKICBoYXNodGFnc19jb3VudHNfYnlfZGF0ZSAlPiUKICBmaWx0ZXIoCiAgICAhc3RyX2RldGVjdChzdHJfdG9fbG93ZXIoaGFzaHRhZ3MpLCBzdHJfdG9fbG93ZXIoIi4qQ09WSUQuKnwuKmNvcm9uYXZpcnVzLioiKSkKICApCikKCiMgRnJvbSBzdW1tYXJ5CmhpdG9zX21pbl9kYXRlPWFzLlBPU0lYY3QoIjIwMjAtMDQtMjUiKQpoaXRvc19tYXhfZGF0ZT1hcy5QT1NJWGN0KCIyMDIwLTA1LTE1IikKCmZpbHRlcmVkX2hhc2h0YWdfY291bnRzX2J5X2RhdGVfcmFuZ2UgPSBhcy5kYXRhLmZyYW1lKAogIGZpbHRlcmVkX2hhc2h0YWdfY291bnRzX2J5X2RhdGUgJT4lCiAgICBmaWx0ZXIoZGF0ZSA+PSBoaXRvc19taW5fZGF0ZSAmIGRhdGUgPD0gaGl0b3NfbWF4X2RhdGUpCikKCiMgQ29uc2lnbyBlbCBoYXNodGFnIG1hcyB1c2FkbyBwYXJhIHVuIGRldGVybWluYWRvIGTDrWEKdG9wX2hhc2h0YWdzX2J5X25ld3NfZGF0ZSA9IGFzLmRhdGEuZnJhbWUoCiAgZmlsdGVyZWRfaGFzaHRhZ19jb3VudHNfYnlfZGF0ZV9yYW5nZSAlPiUgCiAgZ3JvdXBfYnkoZGF0ZSkgJT4lIAogIHRvcF9uKDEsIGNvdW50KQopCgojIE1lIHF1ZWRvIGNvbiBsb3MgcXVlIHRpZW5lbiB2YWxvcmVzIHNpZ25pZmljYXRpdm9zICg+IDMpCnRvcF9oYXNodGFnc19ieV9uZXdzX2RhdGUgPSB0b3BfaGFzaHRhZ3NfYnlfbmV3c19kYXRlW3RvcF9oYXNodGFnc19ieV9uZXdzX2RhdGVbImNvdW50Il0+MyxdCmBgYAoKR3JhZmljYW1vcyBsb3MgaGFzaHRhZ3MgbWFzIHVzYWRvcyBwb3IgZMOtYSAoZXZhbHVhbmRvIGNvbnRlbmlkbykKYGBge3J9CgpwMiA8LSB0b3BfaGFzaHRhZ3NfYnlfbmV3c19kYXRlICU+JQogIGdncGxvdCggYWVzKHg9ZGF0ZSwgeT1jb3VudCwgc2l6ZT1jb3VudCwgY29sb3I9aGFzaHRhZ3MpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZ3RpdGxlKCJNb3N0IHVzZWQgaGFzaHRhZyBieSBkYXRlIikgKwogIHhsYWIoImRhdGUiKSAgKwogIHlsYWIoInRpbWVzIHVzZWQiKSAgKwogIHRoZW1lX2J3KCkKCmdncGxvdGx5KHAyKQpgYGAKCgpgYGB7cn0KCgpgYGAKCg==